Skip to content

Adds "this-is-scam" message context command#1505

Open
Zabuzard wants to merge 5 commits into
developfrom
feature/this_is_scam_command
Open

Adds "this-is-scam" message context command#1505
Zabuzard wants to merge 5 commits into
developfrom
feature/this_is_scam_command

Conversation

@Zabuzard

@Zabuzard Zabuzard commented Jun 19, 2026

Copy link
Copy Markdown
Member

Overview

This adds a new message context command (right click message) called this-is-scam. It acts as the primary way for users to report scam to mods.

Mods then get presented a quick way to handle the scam properly by automatically deleting all messages from the user and putting them under quarantine through a single button press!

grafik

Internally this works by quarantine, ban (delete messages from one day), unban in that order. The user ends up being kicked out of the guild (due to the ban) but can immediately rejoin (due to the unban), but remains quarantined.

Other

The following extra situations are handled gracefully via in-memory caches:

  • multiple users report the same message as scam: only one is being processed
  • a user tries to abuse the command by using it constantly: users are on cooldown for 1 minute

Also, an appropriate entry in the audit-log of the user (/audit) is created.

Attachments are spelled out so it becomes easier for devs later on to edit ScamBlocker accordingly.

Code

The integration is minimal and simple, just a straightforward single class is added ThisIsScamCommand.java, thats it. No config changes, everything easy.

Impressions

Context Menu

grafik

Response

grafik

What mods see

grafik grafik

No scam

grafik

Yes scam

grafik

DM

grafik

Quarantined

grafik

Audit Log

grafik

Edge cases

grafik grafik

Error

grafik

@Zabuzard Zabuzard self-assigned this Jun 19, 2026
@Zabuzard Zabuzard requested a review from a team as a code owner June 19, 2026 12:44
@Zabuzard Zabuzard added new command Add a new command or group of commands to the bot priority: major labels Jun 19, 2026
@sonarqubecloud

Copy link
Copy Markdown

Comment on lines +184 to +185
@SuppressWarnings("squid:S3457") // %n is wrong, markdown must use \n
private static String createDescription(Message target) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't you easily use multiline strings here to make it cleaner and get rid of the suppress warnings?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great idea

Comment on lines +258 to +300
private boolean handleCanQuarantineAndBan(Guild guild, Member target,
ButtonInteractionEvent event) {
Member bot = guild.getSelfMember();
Member moderator = Objects.requireNonNull(event.getMember());
Role quarantinedRole = ModerationUtils.getQuarantinedRole(guild, config).orElse(null);

return ModerationUtils.handleRoleChangeChecks(quarantinedRole, "quarantine", target, bot,
moderator, guild, ACTION_REASON, event)
&& ModerationUtils.handleHasBotPermissions("ban", Permission.BAN_MEMBERS, bot,
guild, event);
}

private RestAction<Boolean> sendQuarantineDm(User target, Guild guild) {
String description =
"""
Hey there, sorry to tell you but unfortunately you have been put under quarantine.
This means you can no longer interact with anyone in the server until you have been unquarantined again.""";

return ModerationUtils.sendModActionDm(ModerationUtils.getModActionEmbed(guild,
ACTION_TITLE, description, ACTION_REASON, true), target);
}

private RestAction<Void> quarantineUser(Guild guild, Member target, Member moderator) {
logger.info(LogMarkers.SENSITIVE,
"'{}' ({}) quarantined the user '{}' ({}) in guild '{}' for reason '{}'.",
moderator.getUser().getName(), moderator.getId(), target.getUser().getName(),
target.getId(), guild.getName(), ACTION_REASON);

actionsStore.addAction(guild.getIdLong(), moderator.getIdLong(), target.getIdLong(),
ModerationAction.QUARANTINE, null, ACTION_REASON);

return guild
.addRoleToMember(target,
ModerationUtils.getQuarantinedRole(guild, config).orElseThrow())
.reason(ACTION_REASON);
}

private RestAction<Void> deleteMessagesByBanAndUnban(Guild guild, User target) {
return guild.ban(target, 1, TimeUnit.DAYS)
.reason(ACTION_REASON)
.flatMap(_ -> guild.unban(target).reason(ACTION_REASON));
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't all of this be reused from the existing quarantine/moderation logic?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not easily. but yeah, some of it can probably be moved around.

the main issue is that we only want part of the behavior but not everything.

so moving the code around could possibly result in making it too complex to understand.

but its a good comment, ill have a second look :)

@firasrg firasrg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @Zabuzard for the great work you've put into this. I'm genuinely impressed by the scope of the changes and the amount of effort behind them.

I've left comments, mostly focused on long-term maintainability and readability. I didn't spend much time reviewing the logic itself, as I trust you've given that aspect the attention it deserves.

* Allows users to report a message as potential scam. Moderators can confirm the report from the
* audit log, causing the author to be quarantined plus message history getting deleted.
*/
public final class ThisIsScamCommand extends BotCommandAdapter implements MessageContextCommand {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use a name like ScamReportCommand for the class, and for the command scam-report

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo all that does is making it more confusing for the user and the devs. a context command needs to be a verb, especially bc they dont have any description in the discord ui

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both work fine, agree it's NIT

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo all that does is making it more confusing for the user and the devs. a context command needs to be a verb, especially bc they dont have any description in the discord ui

Then "Report Scam"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will join the "it's a NIT" team here. It's just the name at the end of the day, and the class has a JavaDoc which makes it easier to understand what this class focuses on.

.build();

private final Config config;
private final ModerationActionsStore actionsStore;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd put these 2 fields config and actionsStore above reportedMessageToTimestamp and userToLastCommandUse, because they represent a higher level

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe, ill see

@surajkumar surajkumar Jun 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT - optional

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is a NIT comment.

At the very least this should be handled by our Spotless plugin.

@SuppressWarnings("squid:S3457") // %n is wrong, markdown must use \n
private static String createDescription(Message target) {
String content = target.getContentStripped();
String description = content.isBlank() ? "(empty message)" : content;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd rather say "empty description"

@Zabuzard Zabuzard Jun 20, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would be confusing as "description" is right in the context of the embed but not in the context of the reading user in discord.
the scan message that was reported is empty, so that is what we need to tell the user.
empty message.

i might improve the wording slightly though:
(message had no text content)

@christolis christolis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thank you for your contribution 👍

* Allows users to report a message as potential scam. Moderators can confirm the report from the
* audit log, causing the author to be quarantined plus message history getting deleted.
*/
public final class ThisIsScamCommand extends BotCommandAdapter implements MessageContextCommand {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will join the "it's a NIT" team here. It's just the name at the end of the day, and the class has a JavaDoc which makes it easier to understand what this class focuses on.

.build();

private final Config config;
private final ModerationActionsStore actionsStore;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is a NIT comment.

At the very least this should be handled by our Spotless plugin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new command Add a new command or group of commands to the bot priority: major

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants